/** 
 * <p>Original Author:  jessefreeman</p>
 * <p>Class File: ImagePreloaderHelper.as
 * 
 * <p>Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:</p>
 * 
 * <p>The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.</p>
 * 
 * <p>THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.</p>
 * 
 * <p>Licensed under The MIT License</p>
 * <p>Redistributions of files must retain the above copyright notice.</p>
 *
 * <p>Revisions<br/> 
 * 	0.1  Initial version Oct 19, 2008</p>
 *
 */

package camo.controllers.helpers
{
	import flash.display.Loader;
	import flash.display.LoaderInfo;
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.IOErrorEvent;
	import flash.events.SecurityErrorEvent;
	import flash.net.URLRequest;
	import flash.system.ApplicationDomain;
	import flash.system.LoaderContext;
	import flash.utils.Dictionary;

	public class ImagePreloaderHelper extends EventDispatcher
	{
		public static const PRELOAD_DONE : String = "preload_done";
		public static const PRELOAD_NEXT : String = "preload_next";
		public static const INIT : String = "init";
		
		public var defaultDelimiter:String = "/";
		private var _loadQueue : Array;
		private var _loading : Boolean;
		public var instances:Array;
		public var instancesReference:Dictionary;
		
		public function ImagePreloaderHelper()
		{
			instances = new Array();
			instancesReference = new Dictionary(true);
			_loadQueue = new Array();
			_loading = false;
		}
		
		/**
		 * 
		 */
		public function load(url : String) : void {
			if(_loading) {
				_loadQueue.push(url);
			}else {
				_loading = true;
				var path : URLRequest = new URLRequest(url);
				var context : LoaderContext = new LoaderContext(false, ApplicationDomain.currentDomain);
				var loader : Loader = new Loader();
				var fileName:String = getFileName(url,defaultDelimiter);
				instances.push(loader);
				instancesReference[fileName] = loader;
				
				addListeners(loader.contentLoaderInfo);

				loader.load(path, context);
			}
		}
		
		public function addToQueue(list : Array) : void {
			_loadQueue = _loadQueue.concat(list);
			
			if(!_loading) {
				preload();
			}
		}
		
		/**
		 * begins preload by seeing if the counter is lower then the total pages to load. If more
		 * loading is needed, the preloader calls the loadPage. If preloading is complete, a
		 * PRELOAD_DONE e is dispatched.
		 */
		internal function preload() : void {

			if(_loadQueue.length > 0) {
				load(_loadQueue[0]);
				dispatchEvent(new Event(PRELOAD_NEXT, true, true));
			}else {
				dispatchEvent(new Event(Event.COMPLETE, true, true));
				
			}
		}
		
		/**
		 * <p>This is called when swf is loaded. After loading, the listeners are removed 
		 * and preload is recalled to continue with the preloading process.</p>
		 */
		public function onLoadComplete(e : Event) : void {
			
			e.stopImmediatePropagation();
			
			// Remove first item in the queue
			_loadQueue = _loadQueue.slice(1);
			
			// Toggle loading to false
			_loading = false;
			
			// Isolate loaded data from e target
			var info : LoaderInfo = e.target as LoaderInfo;
			var loader : Loader = info.loader;
			
			// Remove loading listeners
			removeListeners(info);
			
			// Recall preloader to keep going through the Queue
			preload();
		}
		
		/**
		 * 
		 * @param path
		 * @param delimiter
		 * @return 
		 * 
		 */		
		public function getFileName(path:String, delimiter:String = "/"):String{
			var split:Array = path.split(delimiter);
			var fileName:String = split[split.length -1];
			return fileName;
		}
		
		/**
		 * <p>attaches listeners to LoaderInfo. This is used to streamline the repetitive adding of
		 * listeners in the preload process.<p>
		 * 
		 * @param target
		 * 
		 */		 
		internal function addListeners(target : LoaderInfo) : void {
			target.addEventListener(Event.COMPLETE, onLoadComplete);
			target.addEventListener(IOErrorEvent.IO_ERROR, onIOError);
			target.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onSecurityError);
		}

		/**
		 * <p>removes listeners to LoaderInfo. This is used to streamline the remove of listeners 
		 * from the preload process and frees up memory.</p>
		 */
		internal function removeListeners(target : LoaderInfo) : void {
			target.removeEventListener(Event.COMPLETE, onLoadComplete);
			target.removeEventListener(IOErrorEvent.IO_ERROR, onIOError);
			target.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onSecurityError);
		}
		
		/**
		 * 
		 */
		private function onSecurityError(e : SecurityErrorEvent) : void {
			e.stopImmediatePropagation();
			trace("ExternalSwfLoader: Securty error while loading swf.");
			dispatchEvent(new Event(ImagePreloaderHelper.INIT, true, true));
			
			abortLoad();
		}
		
		/**
		 * 
		 */
		private function onIOError(e : IOErrorEvent) : void {
			e.stopImmediatePropagation();
			trace(e.text);
			dispatchEvent(new Event(ImagePreloaderHelper.INIT, true, true));
			
			abortLoad();
		}
		
		private function abortLoad():void{
			
			// Remove first item in the queue
			_loadQueue = _loadQueue.slice(1);
			
			// Toggle loading to false
			_loading = false;
			
			// Recall preloader to keep going through the Queue
			preload();
		}
		
		public function flush():void{
			// TODO loop through all the instances and null them out
			
			// reset arrays just to make sure
			instances = new Array();
			instancesReference = new Dictionary(true);
			
		}
		
	}
}